import java.util.ArrayList;
import java.util.List;
import java.util.RandomAccess;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * ConditionTest
 * <p>
 * 欢迎跟我一起学习，微信（lvgocc）公众号搜索：星尘的一个朋友
 *
 * @author lvgorice@gmail.com
 * @version 1.0
 * @blog @see http://lvgo.org
 * @CSDN @see https://blog.csdn.net/sinat_34344123
 * @date 2020/12/15
 */
public class ConditionTest {

    public static void main(String[] args) {

        FactoryByCondition factory = new FactoryByCondition();

        // 生产者
        Thread producer = new Thread(() -> {
            try {
                factory.put();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "生产者1");
        producer.start();

        // 生产者 2
        Thread producer2 = new Thread(() -> {
            try {
                factory.put();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "生产者2");
        producer2.start();

        // 消费者
        Thread consumer = new Thread(() -> {
            try {
                factory.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "消费者");
        consumer.start();
        new Thread(() -> {
            while (true) {
                System.out.println("当前线程状态：");
                System.out.println("生产者1：" + producer.getState());
                System.out.println("生产者2：" + producer2.getState());
            }
        }).start();
    }
}


class FactoryByCondition {
    private int[] items = new int[1]; // 数据存储容器(为了演示方便,设置容量最多存储 1 个元素)
    private int size = 0;             // 实际存储大小
    // 创建 Condition 对象
    private Lock lock = new ReentrantLock();
    // 生产者的 Condition 对象
    private Condition producerCondition = lock.newCondition();
    // 消费者的 Condition 对象
    private Condition consumerCondition = lock.newCondition();

    /**
     * 生产方法
     */
    public void put() throws InterruptedException {
        lock.lock();
        try {
            // 循环生产数据
            do {
                while (size == items.length) { // 注意不能是 if 判断
                    // 生产者进入等待
                    System.out.println(Thread.currentThread().getName() + " 进入阻塞");
                    producerCondition.await();
                    System.out.println(Thread.currentThread().getName() + " 被唤醒");
                }
                System.out.println(Thread.currentThread().getName() + " 开始工作");
                items[0] = 1; // 为了方便演示,设置固定值
                size++;
                System.out.println(Thread.currentThread().getName() + " 完成工作");
                // 唤醒消费者
                consumerCondition.signal();
            } while (true);

        } finally {
            lock.unlock();
        }
    }

    /**
     * 消费方法
     */
    public void take() throws InterruptedException {
        lock.lock();
        try {
            // 循环消费数据
            do {

                while (size == 0) {
                    // 消费者阻塞等待
                    consumerCondition.await();
                }
                System.out.println("消费者工作~");
                size--;
                // 唤醒生产者
                producerCondition.signal();

            } while (true);

        } finally {
            lock.unlock();
        }
    }
}
